package com.autoagent.ai_live_master.scriptGeneration.service.impl;


import com.autoagent.ai_live_master.common.base.ApiResponse;
import com.autoagent.ai_live_master.common.model.ByteArrayMultipartFile;
import com.autoagent.ai_live_master.common.model.Payload;
import com.autoagent.ai_live_master.common.utils.AgentClient;
import com.autoagent.ai_live_master.common.utils.KbClient;
import com.autoagent.ai_live_master.common.utils.OssUtil;
import com.autoagent.ai_live_master.common.utils.VoiceProcessUtil;
import com.autoagent.ai_live_master.scriptGeneration.Enum.FileStatusEnum;
import com.autoagent.ai_live_master.scriptGeneration.dto.CompleteScriptsGenerateDTO;
import com.autoagent.ai_live_master.scriptGeneration.dto.CompleteScriptsSaveDTO;
import com.autoagent.ai_live_master.scriptGeneration.dto.FileUploadDTO;
import com.autoagent.ai_live_master.scriptGeneration.entity.CompleteScripts;
import com.autoagent.ai_live_master.scriptGeneration.mapper.CompleteScriptsMapper;
import com.autoagent.ai_live_master.scriptGeneration.service.CompleteScriptsService;
import com.autoagent.ai_live_master.scriptGeneration.utils.FusionDataBuilder;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
public class CompleteScriptsServiceImpl implements CompleteScriptsService {

    @Autowired
    private CompleteScriptsMapper mapper;

    @Autowired
    @Qualifier("completeAgentClient")
    private AgentClient agentClient;

    @Autowired
    @Qualifier("completeScriptsExtractAgentClient")
    private AgentClient completeScriptsExtractAgentClient;

    @Autowired
    private KbClient kbClient;

    @Autowired
    private FusionDataBuilder fusionDataBuilder;

    @Autowired
    private OssUtil ossUtil;

    @Autowired
    private VoiceProcessUtil voiceProcessUtil;

    @Override
    @Async("scriptTaskExecutor")
    public void addScript(FileUploadDTO dto) {
        log.info("开始处理上传文件 - 用户ID: {}, 标题: {}", dto.getUserId(), dto.getTitle());

        String fileType = "";
        String content;

        try {
            // 获取原始文件名
            MultipartFile file = dto.getFile();
            String originalFileName = file.getOriginalFilename();

            if (originalFileName != null && originalFileName.isEmpty()) {
                log.error("上传文件无效：文件名为空");
                throw new RuntimeException("上传文件无效：文件名为空");
            }

            // 获取文件扩展名
            int dotIndex = 0;
            if (originalFileName != null) {
                dotIndex = originalFileName.lastIndexOf('.');
            }
            if (dotIndex > 0) {
                fileType = originalFileName.substring(dotIndex + 1).toLowerCase();
            } else {
                log.error("无法识别文件类型：文件名缺少扩展名");
                throw new RuntimeException("无法识别文件类型：文件名缺少扩展名");
            }

            log.info("文件类型识别为: {}", fileType);

            // 根据文件类型处理内容
            if (isVideoFile(fileType)) {
                // 使用字节数组创建临时文件用于上传
                File tempFile = File.createTempFile("upload_", "_" + fileType);
                try (FileOutputStream fos = new FileOutputStream(tempFile)) {
                    fos.write(dto.getFileContent());
                }
                
                // 上传文件到 OSS
                String fileUrl = ossUtil.uploadLargeFile(new FileInputStream(tempFile), originalFileName);
                tempFile.delete(); // 删除临时文件
                
                log.info("文件已上传至 OSS，地址为: {}", fileUrl);
                log.info("识别为视频文件，开始语音转写处理...");
                content = voiceProcessUtil.processVoiceFile(fileUrl);
            } else if (isDocumentFile(fileType)) {
                log.info("识别为文档文件，开始内容提取处理...");
                log.info("上传文件到知识库");
                String fileId = kbClient.uploadFile(dto.getFileContent(), originalFileName,"id",null);
                log.info("上传文件id，{}", fileId);
                // 构建文档处理的payload
                Payload payload = Payload.builder()
                        .agentId(completeScriptsExtractAgentClient.getAgentId())
                        .userChatInput("提取文档内容")
                        .files(Collections.singletonList(Payload.FileInfo.builder()
                                .fileId(fileId)
                                .fileName(originalFileName)
                                .build()))
                        .build();
                
                // 调用智能体提取文档内容
                log.info("开始调用智能体提取文档内容");
                content = completeScriptsExtractAgentClient.chat_completions(payload);
                log.info("文档内容提取完成，内容长度: {}", content.length());
            } else {
                log.error("不支持的文件类型: {}", fileType);
                throw new RuntimeException("不支持的文件类型，请上传视频或文档文件");
            }

            // 内容处理结果校验
            if (content == null || content.isEmpty()) {
                log.error("文件处理结果为空");
                throw new RuntimeException("文件处理失败，内容为空");
            }

            // 保存处理结果
            CompleteScriptsSaveDTO saveDTO = new CompleteScriptsSaveDTO();
            saveDTO.setUserId(dto.getUserId());
            saveDTO.setFileName(dto.getTitle());
            saveDTO.setContent(content);
            saveScript(saveDTO);
            log.info("文件处理成功，内容已保存到数据库");

        } catch (Exception e) {
            log.error("文件处理失败 - 用户ID: {}, 错误信息: {}", dto.getUserId(), e.getMessage(), e);
            throw new RuntimeException("文件处理失败: " + e.getMessage(), e);
        }
    }

    /**
     * 判断是否为支持的视频类型
     */
    private boolean isVideoFile(String fileType) {
        return Arrays.asList("mp4", "avi", "mov", "wmv", "flv", "mkv").contains(fileType);
    }

    /**
     * 判断是否为支持的文档类型
     */
    private boolean isDocumentFile(String fileType) {
        return Arrays.asList("pdf", "doc", "docx").contains(fileType);
    }


    @Override
    public ApiResponse<Page<CompleteScripts>> getScriptsByUserId(Long userId, Integer pageNum, Integer pageSize) {
        return getScriptsByUserId(userId, pageNum, pageSize, null);
    }

    @Override
    public ApiResponse<Page<CompleteScripts>> getScriptsByUserId(Long userId, Integer pageNum, Integer pageSize, String keyword) {
        log.info("根据用户ID分页获取完整话术列表 - 用户ID: {}, 页码: {}, 每页数量: {}, 关键字: {}", userId, pageNum, pageSize, keyword);
        try {
            if (userId == null) {
                log.warn("用户ID为空");
                return ApiResponse.error(404,"用户未登录");
            }

            // 分页查询用户的话术列表
            Page<CompleteScripts> page = new Page<>(pageNum, pageSize);
            LambdaQueryWrapper<CompleteScripts> scriptQuery = new LambdaQueryWrapper<>();
            scriptQuery.eq(CompleteScripts::getUserId, userId);

            // 如果有关键字，添加filename字段的模糊匹配
            if (keyword != null && !keyword.trim().isEmpty()) {
                scriptQuery.like(CompleteScripts::getFileName, keyword.trim());
            }

            // 按创建时间倒序排列
            scriptQuery.orderByDesc(CompleteScripts::getCreatedAt);

            log.info("分页对象 searchCount={}，isCountSql={}，pageNum={}, pageSize={}",
                    page.searchCount(), page.optimizeCountSql(), page.getCurrent(), page.getSize());
            Page<CompleteScripts> result = mapper.selectPage(page, scriptQuery);

            log.info("完整话术列表获取成功 - 用户ID: {}, 总记录数: {}", userId, result.getTotal());
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("获取完整话术列表失败 - 用户ID: {}, 错误: {}", userId, e.getMessage(), e);
            return ApiResponse.error(404,"获取完整话术列表失败");
        }
    }

    @Override
    public void saveScript(CompleteScriptsSaveDTO dto) {
        log.info("开始保存话术内容 - 用户ID: {}, 标题: {}", dto.getUserId(), dto.getFileName());

        try {
            // 根据userId和title查询现有记录，找最大版本号
            QueryWrapper<CompleteScripts> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", dto.getUserId())
                    .eq("file_name", dto.getFileName())
                    .orderByDesc("version")
                    .last("LIMIT 1");

            CompleteScripts existingScript = mapper.selectOne(queryWrapper);
            int maxVersion = existingScript != null ? existingScript.getVersion() + 1 : 1;

            // 生成安全文件名
            String safeTitle = dto.getFileName().replaceAll("[^a-zA-Z0-9\\u4e00-\\u9fa5]", "_");
            String fileName = String.format("script_%d_%s_v%d.md", dto.getUserId(), safeTitle, maxVersion);

            // 将content转成字节数组（UTF-8编码）
            byte[] bytes = dto.getContent().getBytes(StandardCharsets.UTF_8);

            // 封装成MultipartFile（用你自定义的类）
            MultipartFile multipartFile = new ByteArrayMultipartFile(bytes, "file", fileName, "text/markdown");

            // 上传到OSS
            String ossFilePath = ossUtil.uploadLargeFile(multipartFile);
            log.info("话术内容上传到OSS成功，文件路径: {}", ossFilePath);

            // 新建实体对象并保存数据库
            CompleteScripts script = new CompleteScripts();
            script.setUserId(dto.getUserId());
            script.setFileName(dto.getFileName());
            script.setContent(dto.getContent());
            script.setFilePath(ossFilePath);
            script.setStatus(FileStatusEnum.SUCCESS);
            script.setVersion(maxVersion);

            mapper.insert(script);
            log.info("话术内容保存成功 - ID: {}, OSS路径: {}", script.getId(), ossFilePath);

        } catch (Exception e) {
            log.error("话术内容保存失败 - 用户ID: {}, 错误: {}", dto.getUserId(), e.getMessage(), e);
            throw new RuntimeException("话术内容保存失败", e);
        }
    }



    @Override
    public String generateCompleteScript(CompleteScriptsGenerateDTO dto) {
        log.info("开始生成完整话术内容 - 用户ID: {}", dto.getUserId());

        Map<String,String> state=new HashMap<>();
        // 构建state对象
        Map<String, String> fusionData = fusionDataBuilder.buildFusionState(
                dto.getUserId(),
                dto.getProductDesc(),
                dto.getReferenceScriptIds());

        // 添加话术大纲到state
        state.put("script_outline", dto.getScriptOutline());
        // 直接获取fusion_data中的JSON字符串
        state.put("fusion_data", fusionData.get("fusion_data"));


        // 构建智能体所需的payload
        Payload payload = Payload.builder()
                .agentId(agentClient.getAgentId())
                .userChatInput("根据话术大纲生成完整话术")
                .state(state)
                .build();

        String generatedContent;
        try {
            // 日志记录请求参数
            log.info("[CompleteScripts] 请求payload: {}", payload);
            // 调用智能体同步接口获取处理结果
            generatedContent = agentClient.chat_completions(payload);
            // 日志记录返回结果
            log.info("[CompleteScripts] 智能体返回: {}", generatedContent);
            return generatedContent;
        } catch (Exception e) {
            // 记录异常信息并抛出运行时异常
            log.error("[CompleteScripts] 智能体调用异常: {}", e.getMessage(), e);
            throw new RuntimeException("生成完整话术内容失败", e);
        }
    }

    @Override
    public CompleteScripts getScriptById(Long id) {
        log.info("开始获取话术内容 - 话术ID: {}", id);
        try {
            CompleteScripts script = mapper.selectById(id);
            if (script == null) {
                log.warn("未找到指定的话术 - 话术ID: {}", id);
                return null;
            }
            log.info("成功获取话术内容 - 话术ID: {}", id);
            return script;
        } catch (Exception e) {
            log.error("获取话术内容失败 - 话术ID: {}, 错误信息: {}", id, e.getMessage(), e);
            throw new RuntimeException("获取话术内容失败", e);
        }
    }

    @Override
    public CompleteScripts updateScript(CompleteScriptsSaveDTO dto) {
        log.info("开始更新话术内容 - 话术ID: {}, 用户ID: {}", dto.getId(), dto.getUserId());
        try {
            // 获取原话术内容
            CompleteScripts existingScript = getScriptById(dto.getId());

            //删除原有oss内容
            extracted(existingScript);

            // 将新的content写入文件并上传到OSS
            String newOssFilePath = null;
            try {
                log.info("开始将更新后的话术内容上传到OSS");

                // 创建临时文件
                MultipartFile multipartFile = getMultipartFile(dto, existingScript);

                // 上传到OSS
                newOssFilePath = ossUtil.uploadLargeFile(multipartFile);
                log.info("更新后的话术内容上传到OSS成功，文件路径: {}", newOssFilePath);

            } catch (Exception e) {
                log.error("更新后的话术内容上传到OSS失败", e);
                throw new RuntimeException("更新后的话术内容上传到OSS失败: " + e.getMessage());
            }

            // 创建新的CompleteScripts对象
            CompleteScripts script = new CompleteScripts();
            script.setId(dto.getId());
            script.setUserId(dto.getUserId());
            script.setFileName(dto.getFileName());
            script.setContent(dto.getContent());
            script.setFilePath(newOssFilePath);  // 设置新的OSS文件路径
            script.setVersion(existingScript.getVersion() + 1);

            // 更新到数据库
            mapper.updateById(script);

            log.info("话术内容更新成功 - ID: {}, 新OSS路径: {}", script.getId(), newOssFilePath);
            return script;
        } catch (Exception e) {
            log.error("话术内容更新失败 - 话术ID: {}, 错误: {}", dto.getId(), e.getMessage(), e);
            throw new RuntimeException("话术内容更新失败", e);
        }
    }

    private MultipartFile getMultipartFile(CompleteScriptsSaveDTO dto, CompleteScripts existingScript) {
        int newVersion = existingScript.getVersion() + 1;
        String fileName = String.format("script_%s_%s_v%d.md", dto.getUserId(),
                dto.getFileName().replaceAll("[^a-zA-Z0-9\\u4e00-\\u9fa5]", "_"), newVersion);
        byte[] bytes = dto.getContent().getBytes(StandardCharsets.UTF_8);

        // 封装成MultipartFile（用你自定义的类）
        return new ByteArrayMultipartFile(bytes, "file", fileName, "text/markdown");
    }

    @Override
    public void deleteScript(Long id) {
        log.info("开始删除话术 - 话术ID: {}", id);
        try {
            // 获取原话术内容
            CompleteScripts existingScript = getScriptById(id);

            //删除原有oss内容
            extracted(existingScript);
            // 从数据库中删除
            mapper.deleteById(id);
            
            log.info("话术删除成功 - ID: {}", id);
        } catch (Exception e) {
            log.error("话术删除失败 - 话术ID: {}, 错误: {}", id, e.getMessage(), e);
            throw new RuntimeException("话术删除失败", e);
        }
    }

    private void extracted(CompleteScripts existingScript) {
        if (existingScript == null) {
            throw new RuntimeException("未找到指定的话术");
        }
        // 删除原有的OSS文件
        if (existingScript.getFilePath() != null && !existingScript.getFilePath().isEmpty()) {
            try {
                log.info("开始删除原有OSS文件: {}", existingScript.getFilePath());

                // 从完整的OSS URL中提取objectName
                String ossUrl = existingScript.getFilePath();
                String objectName = ossUtil.extractObjectNameFromUrl(ossUrl);

                if (objectName != null && !objectName.isEmpty()) {
                    ossUtil.deleteFile(null, objectName);  // bucketName传null使用默认bucket
                    log.info("原有OSS文件删除成功");
                } else {
                    log.warn("无法从OSS URL中提取objectName: {}", ossUrl);
                }
            } catch (Exception e) {
                log.warn("删除原有OSS文件失败，继续执行更新操作: {}", e.getMessage());
            }
        }
    }
}